/*
 * QuadWorker.java
 *
 * Created on May 29, 2005, 3:51 PM
 */

package aa.application.AdaptiveQuad;

import aa.core.Actor;
import aa.core.ActorName;
import aa.core.CreateActorException;
import java.lang.Math;

/**
 *
 * @author  xinghuizhao
 */
public class QuadWorker extends Actor{
    
    int numResponses; //number of response it has received if it is fib actor
    
    double partialResponse; 
    
    Double tolerance;
    
    /** The first response we have received from a child fib actor. We save
     *  this value until we receive the second response, and send our clint 
     *  the sum of both values 
     */
    
    ActorName client; //the actor which is suppose to receive result from this actor
    
    String meth; //method to invoke on teh receiving client (if this is a worker fib actor)
    
    /** Creates a new instance of QuadWorker */
    public QuadWorker(Double p_douTolerance) {
        tolerance = p_douTolerance;
    }
    
    public QuadWorker(ActorName p_anClient,String p_strMeth,Double p_douTolerance) {
        client = p_anClient;
        meth = p_strMeth;
        numResponses = 0;
        tolerance = p_douTolerance;
    }
    
    /** This method is called to do the quadrature computation
     * a: lower bound
     * b: upper bound
     * tolerance: the error tolerance
     * p_anClient: the actor which is suppose to receive result from this actor
     * p_strMeth: the name of the method to calculate result in client actor
     */
    public void quadrature(Double a,Double b,ActorName p_anClient,String p_strMeth){
        double quadResult = trapezoid(a,b);
        if(Math.abs(quadResult-divideSum(a,b))<tolerance.doubleValue()){
            send(p_anClient,p_strMeth,new Double(quadResult));
        }else{
            try{
                ActorName newChild=create("aa.application.AdaptiveQuad.QuadWorker",p_anClient,p_strMeth,tolerance);
                
                Double mid = new Double((a.doubleValue()+b.doubleValue())/2);
                
                quadrature(a,mid,newChild,p_strMeth);
                
                quadrature(mid,b,newChild,p_strMeth);
                
            }catch (CreateActorException e){
                
            }
            
        }
    }
    
    /** The function */
    public double func(double x){
        return x*x;
    }
    
    /** Calculate the area of a trapezoid */
    public double trapezoid(Double a,Double b){
        double aValue = a.doubleValue();
        double bValue = b.doubleValue();
        return (func(aValue)+func(bValue))*(bValue-aValue)/2;
    }
    
    /** Calculate the sum of areas of two sub trapezoids*/
    public double divideSum(Double a,Double b){
        double aValue = a.doubleValue();
        double bValue = b.doubleValue();
        double midpoint = (aValue+bValue)/2;
        Double dmid = new Double(midpoint);
        return (trapezoid(a,dmid)+trapezoid(dmid,b));
    }
         
    /** This method is called from another child actor to pass a partial result.
     *  We wait until we have two such results, add them, and return the result to 
     *  client.
     *
     */
    
    public void result(Double p_douVal){
        if (numResponses==0){
            numResponses++;
            partialResponse = p_douVal.doubleValue();
        }
        else {
            //send the answer
            double myResult = p_douVal.doubleValue()+partialResponse;
            send(client,meth,new Double(myResult));
            destroy("Result actor no longer accessible, removing...");
            System.out.println( myResult +"  -- "+System.currentTimeMillis());
        }
    }
    
}
